{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 并发和并行\n",
    "并发是指计算机看起来同一时刻运行多个程序。即使在单核cpu上，操作系统也会以分时间片的方式轮流执行多个程序，由于cpu速度非常，所以宏观上就是多个程序看起来同时在运行。\n",
    "\n",
    "并行是指计算机真的是同一时刻运行多个程序。在多核cpu的情况下就可以做到微观上同一时刻运行多个程序。\n",
    "\n",
    "并行可以显著的提高程序任务的执行速度。而并发无论分成多少个线程，但是整体的任务执行速度并没有多少提升。即使如此，并发的意义是很大的，它实现了即使在单cpu的情况下，多个程序可以同时运行，实现了对各种资源的充分里利用。在设计程序时要搞清楚并发和并行的区别，以便做出合适的选择。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU内核数量：8\n"
     ]
    }
   ],
   "source": [
    "#查看cpu内核\n",
    "from multiprocessing import cpu_count\n",
    "print(\"CPU内核数量：%s\" % cpu_count()) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 多进程\n",
    "在计算机操作系统中，一个进程就是一个运行着的程序，多进程技术就是如何通过运行多个程序来完成自己的任务。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 多线程\n",
    "在程序中，一个程序里面可能有多个线程，每个线程负责不同的任务，当一个线程处于阻塞状态时（比如等待一个网络数据），其它线程还可以正常运行（比如UI线程）。想并行执行线程并不容易，大部分还是并发的概念。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "卖薯0哥卖了一个红薯，还剩34个红薯\n",
      "卖薯5哥卖了一个红薯，还剩33个红薯\n",
      "卖薯2哥卖了一个红薯，还剩32个红薯\n",
      "卖薯1哥卖了一个红薯，还剩31个红薯\n",
      "卖薯3哥卖了一个红薯，还剩30个红薯卖薯4哥卖了一个红薯，还剩30个红薯\n",
      "\n",
      "卖薯0哥卖了一个红薯，还剩28个红薯\n",
      "卖薯5哥卖了一个红薯，还剩27个红薯\n",
      "卖薯2哥卖了一个红薯，还剩26个红薯\n",
      "卖薯1哥卖了一个红薯，还剩25个红薯\n",
      "卖薯3哥卖了一个红薯，还剩24个红薯\n",
      "卖薯4哥卖了一个红薯，还剩23个红薯\n",
      "卖薯0哥卖了一个红薯，还剩22个红薯卖薯5哥卖了一个红薯，还剩22个红薯\n",
      "\n",
      "卖薯2哥卖了一个红薯，还剩20个红薯\n",
      "卖薯1哥卖了一个红薯，还剩19个红薯\n",
      "卖薯3哥卖了一个红薯，还剩18个红薯\n",
      "卖薯4哥卖了一个红薯，还剩17个红薯\n",
      "卖薯5哥卖了一个红薯，还剩16个红薯卖薯0哥卖了一个红薯，还剩16个红薯\n",
      "\n",
      "卖薯2哥卖了一个红薯，还剩15个红薯\n",
      "卖薯1哥卖了一个红薯，还剩13个红薯\n",
      "卖薯3哥卖了一个红薯，还剩12个红薯\n",
      "卖薯4哥卖了一个红薯，还剩11个红薯\n",
      "卖薯5哥卖了一个红薯，还剩10个红薯\n",
      "卖薯2哥卖了一个红薯，还剩9个红薯卖薯0哥卖了一个红薯，还剩9个红薯\n",
      "\n",
      "卖薯1哥卖了一个红薯，还剩7个红薯\n",
      "卖薯3哥卖了一个红薯，还剩6个红薯卖薯4哥卖了一个红薯，还剩6个红薯\n",
      "\n",
      "卖薯5哥卖了一个红薯，还剩4个红薯\n",
      "卖薯2哥卖了一个红薯，还剩3个红薯卖薯0哥卖了一个红薯，还剩3个红薯\n",
      "\n",
      "卖薯1哥卖了一个红薯，还剩1个红薯\n",
      "卖薯3哥卖了一个红薯，还剩0个红薯卖薯4哥卖了一个红薯，还剩0个红薯\n",
      "\n",
      "卖薯5哥卖了一个红薯，还剩0个红薯\n",
      "卖薯2哥卖了一个红薯，还剩0个红薯卖薯0哥卖了一个红薯，还剩0个红薯\n",
      "\n",
      "卖薯1哥卖了一个红薯，还剩0个红薯\n"
     ]
    }
   ],
   "source": [
    "#假设我们开了地摊卖烤红薯,开几个线程同时卖红薯，观察会出现什么情况\n",
    "#结果会发现大家卖的顺序可能是乱的，甚至还会出现超卖的情况\n",
    "#这是因为在多线程是大家争用了共同的资源sweetpotato，造成了难以预料的问题\n",
    "import threading,time\n",
    "sweetpotato = 40\n",
    "def sale():\n",
    "    global sweetpotato\n",
    "    #每个线程不断的每隔2秒卖一个红薯直到红薯卖完\n",
    "    while sweetpotato>0:\n",
    "        sweetpotato = sweetpotato - 1\n",
    "        time.sleep(1)\n",
    "        print('{}卖了一个红薯，还剩{}个红薯'.format(threading.current_thread().name, sweetpotato))\n",
    "        \n",
    "#创建n个卖薯哥\n",
    "salethreads = [threading.Thread(target=sale,name=\"卖薯{}哥\".format(n)) for n in range(6)] \n",
    "#一个个喊卖薯哥开始卖红薯\n",
    "for salethread in salethreads:\n",
    "    salethread.start()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "卖薯0哥卖了一个红薯，还剩39个红薯\n",
      "卖薯1哥卖了一个红薯，还剩38个红薯\n",
      "卖薯2哥卖了一个红薯，还剩37个红薯\n",
      "卖薯3哥卖了一个红薯，还剩36个红薯\n",
      "卖薯4哥卖了一个红薯，还剩35个红薯\n",
      "卖薯5哥卖了一个红薯，还剩34个红薯\n",
      "卖薯0哥卖了一个红薯，还剩33个红薯\n",
      "卖薯1哥卖了一个红薯，还剩32个红薯\n",
      "卖薯2哥卖了一个红薯，还剩31个红薯\n",
      "卖薯3哥卖了一个红薯，还剩30个红薯\n",
      "卖薯4哥卖了一个红薯，还剩29个红薯\n",
      "卖薯5哥卖了一个红薯，还剩28个红薯\n",
      "卖薯0哥卖了一个红薯，还剩27个红薯\n",
      "卖薯1哥卖了一个红薯，还剩26个红薯\n",
      "卖薯2哥卖了一个红薯，还剩25个红薯\n",
      "卖薯3哥卖了一个红薯，还剩24个红薯\n",
      "卖薯4哥卖了一个红薯，还剩23个红薯\n",
      "卖薯5哥卖了一个红薯，还剩22个红薯\n",
      "卖薯0哥卖了一个红薯，还剩21个红薯\n",
      "卖薯1哥卖了一个红薯，还剩20个红薯\n",
      "卖薯2哥卖了一个红薯，还剩19个红薯\n",
      "卖薯3哥卖了一个红薯，还剩18个红薯\n",
      "卖薯4哥卖了一个红薯，还剩17个红薯\n",
      "卖薯5哥卖了一个红薯，还剩16个红薯\n",
      "卖薯0哥卖了一个红薯，还剩15个红薯\n",
      "卖薯1哥卖了一个红薯，还剩14个红薯\n",
      "卖薯2哥卖了一个红薯，还剩13个红薯\n",
      "卖薯3哥卖了一个红薯，还剩12个红薯\n",
      "卖薯4哥卖了一个红薯，还剩11个红薯\n",
      "卖薯5哥卖了一个红薯，还剩10个红薯\n",
      "卖薯0哥卖了一个红薯，还剩9个红薯\n",
      "卖薯1哥卖了一个红薯，还剩8个红薯\n",
      "卖薯2哥卖了一个红薯，还剩7个红薯\n",
      "卖薯3哥卖了一个红薯，还剩6个红薯\n",
      "卖薯4哥卖了一个红薯，还剩5个红薯\n",
      "卖薯5哥卖了一个红薯，还剩4个红薯\n",
      "卖薯0哥卖了一个红薯，还剩3个红薯\n",
      "卖薯1哥卖了一个红薯，还剩2个红薯\n",
      "卖薯2哥卖了一个红薯，还剩1个红薯\n",
      "卖薯3哥卖了一个红薯，还剩0个红薯\n"
     ]
    }
   ],
   "source": [
    "#为了解决资源的访问冲突，我们通过锁机制让多个线程有条不紊的卖红薯。\n",
    "#threading.RLock()提供一个\n",
    "import threading,time\n",
    "sweetpotato = 40\n",
    "def sale(lock):\n",
    "    global sweetpotato\n",
    "    #每个线程不断的每隔2秒卖一个红薯直到红薯卖完\n",
    "    while sweetpotato>0:\n",
    "        if lock.acquire():\n",
    "            if sweetpotato>0:\n",
    "                sweetpotato -= 1\n",
    "                time.sleep(1)\n",
    "                print('{}卖了一个红薯，还剩{}个红薯'.format(threading.current_thread().name, sweetpotato))\n",
    "            lock.release()\n",
    "            time.sleep(1)\n",
    "#创建n个卖薯哥\n",
    "lock = threading.RLock()\n",
    "salethreads = [threading.Thread(target=sale,args=(lock,),name=\"卖薯{}哥\".format(n)) for n in range(6)] \n",
    "#一个个喊卖薯哥开始卖红薯\n",
    "for salethread in salethreads:\n",
    "    salethread.start()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#随着红薯规模的扩大，有人烤红薯有人卖红薯\n",
    "#所以我们要定义两个线程，一个烤红薯一个卖红薯\n",
    "#然后招聘10个员工，编号奇数烤红薯，编号偶数卖红薯\n",
    "#烤红薯的人每次花5秒钟烤5个红薯，卖红薯的人一秒钟卖1个红薯\n",
    "import threading,time\n",
    "roasted_sweetpatato = 0\n",
    "\n",
    "def roast(lock):\n",
    "    global roasted_sweetpatato\n",
    "    if lock.acquire():\n",
    "        time.sleep(5)\n",
    "        roasted_sweetpatato += 5\n",
    "        print(\"{}烤了5个红薯，现在一共是{}个\".format(threading.current_thread.name,roasted_sweetpatato))\n",
    "        lock.release()\n",
    "\n",
    "def sale(lock):\n",
    "    global roasted_sweetpatato\n",
    "    if roasted_sweetpatato>0 and lock.acquire():\n",
    "        time.sleep(1)\n",
    "        if roasted_sweetpatato>0:\n",
    "            roasted_sweetpatato -= 1\n",
    "            print(\"{}卖了1个红薯，现在一共是{}个\".format(threading.current_thread.name,roasted_sweetpatato))\n",
    "        lock.release()\n",
    "        \n",
    "lock = threading.Lock()\n",
    "\n",
    "threads = []\n",
    "for index in range(4):\n",
    "    threads.append(threading.Thread(target=(sale if index%2 else roast),\n",
    "                               args=(lock,),\n",
    "                               name=(\"烤薯{}姐\" if index%2 else \"卖薯{}哥\").format(index)))\n",
    "for thread in threads:\n",
    "    thread.start()\n",
    "\n",
    "for thread in threads:\n",
    "    thread.join()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
